//    entity language compiler Copyright (C) 2011 Vincent Belliard

//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation version 3 of the License.

//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.

//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

class T_object_class ;
class T_global ;
class T_type ;
class T_expression ;
class T_entity_program ;

enum T_entity_compiler_item
	{
	entity_compiler_item_eof,
	entity_compiler_item_identifier,
	entity_compiler_item_integer,
	entity_compiler_item_real,
	entity_compiler_item_string,
	entity_compiler_item_character,
	entity_compiler_item_left_brace,
	entity_compiler_item_right_brace,
	entity_compiler_item_left_bracket,
	entity_compiler_item_right_bracket,
	entity_compiler_item_left_left_bracket,
	entity_compiler_item_right_right_bracket,
	entity_compiler_item_left_parenthesis,
	entity_compiler_item_right_parenthesis,
	entity_compiler_item_semicolon,
	entity_compiler_item_colon,
	entity_compiler_item_equal,
	entity_compiler_item_equal_equal,
	entity_compiler_item_add,
	entity_compiler_item_add_add,
	entity_compiler_item_add_equal,
	entity_compiler_item_minus,
	entity_compiler_item_minus_greater,
	entity_compiler_item_minus_minus,
	entity_compiler_item_minus_equal,
	entity_compiler_item_star,
	entity_compiler_item_star_equal,
	entity_compiler_item_slash,
	entity_compiler_item_slash_equal,
	entity_compiler_item_percent,
	entity_compiler_item_percent_equal,
	entity_compiler_item_ampersand,
	entity_compiler_item_ampersand_equal,
	entity_compiler_item_circumflex,
	entity_compiler_item_circumflex_equal,
	entity_compiler_item_pipe,
	entity_compiler_item_pipe_pipe,
	entity_compiler_item_pipe_equal,
	entity_compiler_item_pipe_pipe_equal,
	entity_compiler_item_less,
	entity_compiler_item_less_equal,
	entity_compiler_item_less_less,
	entity_compiler_item_less_less_equal,
	entity_compiler_item_greater,
	entity_compiler_item_greater_equal,
	entity_compiler_item_greater_greater,
	entity_compiler_item_greater_greater_equal,
	entity_compiler_item_exclamation_mark,
	entity_compiler_item_exclamation_mark_equal,
	entity_compiler_item_comma,
	entity_compiler_item_dot,
	entity_compiler_item_dot_dot,
	entity_compiler_item_dot_dot_dot,
	entity_compiler_item_question_mark,
	entity_compiler_item_tilde
	} ;

class T_entity_location
	{
public:
	T_string file_name ;
	T_string_iterator location ;
	T_entity_location(void) {}
	T_entity_location(const T_entity_location &ref) : file_name(ref.file_name), location(ref.location) {}
	T_entity_location(const T_string &new_file_name, const T_string_iterator &new_location) : file_name(new_file_name), location(new_location) {}
	void set(const T_string &new_file_name, const T_string_iterator &new_location) { file_name.set(new_file_name) ; location.set(new_location) ; }
	} ;

class T_entity_file : public LINK<T_entity_file>
	{
public:
	T_string file_name ;
	T_string buffer ;
	T_entity_file(const T_string new_file_name) { file_name.set(new_file_name) ; }
	} ;

class T_entity_compiler
	{
public:
	LIST<T_entity_file> files ;
	T_string file_name ;
	T_string_iterator current ;
	T_string_iterator location ;
	int errors_count ;
	T_entity_compiler_item current_item ;
	T_string string ;
	unsigned long long integer ;
	double real ;
	unsigned long character ;
	T_entity_compiler(void) ;
	~T_entity_compiler() ;
	void add_file(const T_string new_file_name) ;
	void add_error(const char *format, ...) ;
	void add_error(T_entity_location &where, const char *format, ...) ;
	void add_error(T_string_iterator &where, const char *format, ...) ;
	int is_identifier_character(unsigned loc, int first) ;
	int is_integer_character(unsigned loc) { return (loc >= '0') && (loc <= '9') ; }
	int is_hexa_character(unsigned loc) { return (loc >= 'A') && (loc <= 'F') ; }
	void reduce_identifier(void) ;
	void reduce_full_identifier(void) ;
	void reduce_integer(void) ;
	void reduce_character(void) ;
	void reduce_string(void) ;
	void next_item(void) ;
	void goto_right_parenthesis(void) ;
	void skip_semicolon(void) ;
	int skip_colon(void) ;
	int skip_comma(void) ;
	void skip_right_brace(void) ;
	void skip_right_bracket(void) ;
	void skip_right_parenthesis(void) ;
	void skip_attributes_definition(void) ;
	int parse_keyword(const char *keyword) ;
	int parse_semicolon(void) { if (current_item != entity_compiler_item_semicolon) return FALSE ; next_item() ; return TRUE ; }
	int parse_colon(void) { if (current_item != entity_compiler_item_colon) return FALSE ; next_item() ; return TRUE ; }
	int parse_left_parenthesis(void) { if (current_item != entity_compiler_item_left_parenthesis) return FALSE ; next_item() ; return TRUE ; }
	int parse_right_parenthesis(void) { if (current_item != entity_compiler_item_right_parenthesis) return FALSE ; next_item() ; return TRUE ; }
	int parse_left_brace(void) { if (current_item != entity_compiler_item_left_brace) return FALSE ; next_item() ; return TRUE ; }
	int parse_right_brace(void) { if (current_item != entity_compiler_item_right_brace) return FALSE ; next_item() ; return TRUE ; }
	int is_eof(void) { return current_item == entity_compiler_item_eof ; }
	int is_identifier(void) { return current_item == entity_compiler_item_identifier ; }
	void compile_source_files(void) ;
	void compile_source(T_entity_program *program) ;
	T_type *parse_type(void) ;
	T_type *parse_compound_type(void) ;
	T_expression *parse_expression(void) ;
	T_expression *parse_test_and_expression(void) ;
	T_expression *parse_test_expression(void) ;
	T_expression *parse_assign_expression(void) ;
	T_expression *parse_logical_or_expression(void) ;
	T_expression *parse_logical_and_expression(void) ;
	T_expression *parse_comparison_expression(void) ;
	T_expression *parse_arithmetic_or_expression(void) ;
	T_expression *parse_arithmetic_xor_expression(void) ;
	T_expression *parse_arithmetic_and_expression(void) ;
	T_expression *parse_shift_expression(void) ;
	T_expression *parse_additive_expression(void) ;
	T_expression *parse_multiplicative_expression(void) ;
	T_expression *parse_left_unary_expression(void) ;
	T_expression *parse_right_unary_expression(void) ;
	T_expression *parse_base_expression(void) ;
	int can_assign_to(T_type *src, T_type *dst) ;
	void parse_module(T_entity_program *program) ;
	} ;

class T_entity_program
	{
public:
	T_string entry_name ;
	T_object_class *entry ;
	LIST<T_object_class> object_classes ;
	LIST<T_global> globals ;
	T_object_class *class_class ;
	T_object_class *boolean_class ;
	T_object_class *integer_8_class ;
	T_object_class *integer_16_class ;
	T_object_class *integer_32_class ;
	T_object_class *integer_64_class ;
	T_object_class *natural_integer_8_class ;
	T_object_class *natural_integer_16_class ;
	T_object_class *natural_integer_32_class ;
	T_object_class *natural_integer_64_class ;
	T_object_class *real_64_class ;
	T_object_class *character_class ;
	T_object_class *string_class ;
	T_object_class *dynamic_string_class ;
	T_object_class *string_iterator_class ;
	T_object_class *list_link_class ;
	T_object_class *vector_item_class ;
	T_object_class *vector_item_reference_class ;
	T_object_class *vector_class ;
	T_object_class *type_class ;
	T_object_class *object_class_field_class ;
	T_object_class *object_class_class ;
	int last_index ;
	T_entity_program(void) ;
	int get_next_index(void) { return ++last_index ; }
	T_object_class *add_object_class(const T_entity_location &new_location, int new_entity, const T_string new_name, T_object_class *base_class) ;
	T_object_class *search_class(const T_string &name) ;
	T_global *search_global(const T_string &name) ;
	int is_character(const T_type *type) ;
	int is_integer(const T_type *type) ;
	int is_number(const T_type *type) ;
	int is_increment(const T_type *type) ;
	void generate_post_increment(FILE *file, T_expression *expression) ;
	void generate_post_decrement(FILE *file, T_expression *expression) ;
	void init_builtins(void) ;
	void dump(FILE *file) const ;
	void verify_semantic(T_entity_compiler *compiler) ;
	int generate(const T_string &file_name) ;
	} ;
